package dao.hibernate;

import java.util.ArrayList;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.hibernate.SessionFactory;
import service.configuration.IAsofConfig;
import service.configuration.IBlockConfig;
import service.configuration.IConfiguration;
import service.configuration.IFieldConfig;
import service.configuration.ISheetConfig;
import service.configuration.NamingUtil;


public abstract class HibernateUtil {
	
	protected IConfiguration config;
	protected SessionFactory sessionFactory;
	protected int jdbcBatchSize;
	protected org.hibernate.cfg.Configuration hibernateConfig;
	
	
	/* initialise le sessionFactory d'hibernate après avoir lu la configuration principale du fichier
	   hibernate.cfg.xml et avoir ajouté les mappings des entitités dynamiquement
	*/
	
	public HibernateUtil(IConfiguration config, String configFilePath) {
	
		this.config = config;
		
		// on crée la configuration hibernate :
		hibernateConfig = new org.hibernate.cfg.Configuration().
		configure(configFilePath);

		jdbcBatchSize = Integer.valueOf(hibernateConfig.getProperty("hibernate.jdbc.batch_size"));
	}
	
	
	
	public IConfiguration getConfig() {
		return config;
	}


	public org.hibernate.cfg.Configuration getHibernateConfig() {
		return hibernateConfig;
	}



	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public int getJdbcBatchSize() {
		return jdbcBatchSize;
	}
	

	protected void addEnumProperty(Document document, String name,
			String column, String notNull, String enumClass) {
		
		Element entity = document.getRootElement().element("class");
		addEnumProperty(entity, name, column, notNull, enumClass);
	}
	
	protected void addEnumProperty(Element entity, String name,
			String column, String notNull, String enumClass) {

		Element property = entity.addElement("property")
		.addAttribute("name", name)
		.addAttribute("column", column)
		.addAttribute("not-null", notNull);
		
		Element type = property.addElement("type")
					   .addAttribute("name", "org.hibernate.type.EnumType");

		type.addElement("param")
		.addAttribute("name", "enumClass")
		.setText(enumClass);
		
		type.addElement("param")
		.addAttribute("name", "type")
		.setText("12"); // correspond à java.type.sql.VARCHAR
	}
	
	
	
	
	protected void addProperty(Document document, String name, String type, String column) {
		Element entity = document.getRootElement().element("class");
		addProperty(entity, name, type, column);
	}
	
	protected void addKeyProperty(Document document, String name, String type, String column) {
		Element entity = document.getRootElement().element("class");
		addKeyProperty(entity, name, type, column);
	}
	
	protected void addKeyProperty(Element entity, String name, String type, String column) {
		addElement(entity, "property", name, type, column);
	}
	
	protected void addProperty(Element entity, String name, String type, String column) {
		addElement(entity, "property", name, type, column);
	}
	
	protected Element addElement(Element entity, String elementName, String name, String type, String column) {
		return entity.addElement(elementName)
		.addAttribute("name", name)
		.addAttribute("type", type)
		.addAttribute("column", column);
	}
	
	
	/* genere un document xml de mapping hibernate à partir de la configuration
	   d'un sheetConfig qui permet de décrire une entité hibernate commune REF et ASOF */
	protected Document createSheetMappingDocument(ISheetConfig sheetConfig) {
		Document document  = DocumentHelper.createDocument();

		Element root = document.addElement("hibernate-mapping");
		Element entity = root.addElement("class")
						 .addAttribute("entity-name", sheetConfig.getName())
						 .addAttribute("table", sheetConfig.getTable());
		addElement(entity, "id", NamingUtil.CODE, "string", sheetConfig.getCode());
	
		for(IBlockConfig blockConfig : sheetConfig.getBlockConfigs()) {
			for(IFieldConfig fieldConfig : blockConfig.getFieldConfigs()) {
				addProperty(entity, fieldConfig.getName(),
									fieldConfig.getHibernateType(),
									fieldConfig.getColumn());
			}
		}
		
		addProperty(entity, NamingUtil.VERSION, "string", sheetConfig.getVersion());

		return document;
	}
	
	
	
	protected Document createHibernatePersonSheetMapping() {
		IAsofConfig asofConfig = config.getConfig();
		return createSheetMappingDocument(asofConfig.getPersonSheetConfig());
	}
	
	
	
	/* génère les documents xml de mapping hibernate à partir de la configuration ASOF
	   et les ajoute directement à la configuration hibernate de REF
	*/
	protected List<Document> createHibernateSheetsMappings() {
		List<Document> mappings = new ArrayList<Document>();
		Document document = null;
		
		// ajoute les mappings pour tous l types de fiches :
		for(ISheetConfig sheetConfig : config.getConfig().getSheetConfigs()) {
			document = createSheetMappingDocument(sheetConfig);
			mappings.add(document);
			//hibernateConfig.addDocument(writer.write(document));
		}
		
		return mappings;
	}
	
}
